import re
import uuid
from typing import Dict, Any, List, Optional, Tuple
from abc import ABC, abstractmethod

class ChunkingStrategy(ABC):
    """切片策略抽象基类"""
    
    @abstractmethod
    def chunk(self, text: str, structure: Dict[str, Any] = None) -> List[Dict[str, Any]]:
        """执行切片操作"""
        pass

class FixedLengthChunking(ChunkingStrategy):
    """固定长度切片策略"""
    
    def __init__(self, chunk_size: int = 500, overlap_size: int = 50):
        self.chunk_size = chunk_size
        self.overlap_size = overlap_size
    
    def chunk(self, text: str, structure: Dict[str, Any] = None) -> List[Dict[str, Any]]:
        """按固定长度切片"""
        
        if not text:
            return []
        
        chunks = []
        start = 0
        chunk_id = 0
        
        while start < len(text):
            # 确定切片结束位置
            end = start + self.chunk_size
            
            if end >= len(text):
                # 最后一个切片
                chunk_text = text[start:]
            else:
                # 寻找合适的断点（避免截断单词或句子）
                chunk_text = text[start:end]
                
                # 尝试在句号、换行符等位置断开
                better_end = self._find_better_breakpoint(text, start, end)
                if better_end > start:
                    chunk_text = text[start:better_end]
                    end = better_end
            
            if chunk_text.strip():
                chunk = {
                    'chunk_id': f'chunk_{chunk_id:03d}',
                    'content': chunk_text.strip(),
                    'metadata': {
                        'chunk_type': 'fixed_length',
                        'start_pos': start,
                        'end_pos': end,
                        'word_count': len(chunk_text.split()),
                        'char_count': len(chunk_text),
                        'level': 0
                    }
                }
                chunks.append(chunk)
                chunk_id += 1
            
            # 计算下一个切片的起始位置（考虑重叠）
            start = max(start + 1, end - self.overlap_size)
        
        return chunks
    
    def _find_better_breakpoint(self, text: str, start: int, end: int) -> int:
        """寻找更好的断点"""
        
        # 在最后100个字符中寻找断点
        search_start = max(start, end - 100)
        search_text = text[search_start:end]
        
        # 优先级：句号 > 换行符 > 其他标点 > 空格
        breakpoints = [
            (r'[.!?]\s+', 1),  # 句号等后面的空格
            (r'\n\s*', 0),     # 换行符
            (r'[,;:]\s+', 1),  # 其他标点后的空格
            (r'\s+', 0)        # 空格
        ]
        
        for pattern, offset in breakpoints:
            matches = list(re.finditer(pattern, search_text))
            if matches:
                # 选择最后一个匹配
                last_match = matches[-1]
                return search_start + last_match.end() - offset
        
        return end

class ContentTypeChunking(ChunkingStrategy):
    """按内容类型切片策略"""
    
    def __init__(self):
        self._compile_patterns()
    
    def _compile_patterns(self):
        """编译内容识别模式"""
        
        # 标题模式
        self.title_patterns = [
            re.compile(r'^#{1,6}\s+(.+)$', re.MULTILINE),  # Markdown标题
            re.compile(r'^\s*第[一二三四五六七八九十\d]+[章节部分]\s*(.*)$', re.MULTILINE),  # 中文章节
            re.compile(r'^\s*Chapter\s+\d+\s*(.*)$', re.MULTILINE | re.IGNORECASE),  # 英文章节
            re.compile(r'^\s*\d+\.\s+(.+)$', re.MULTILINE),  # 数字标题
            re.compile(r'^\s*[一二三四五六七八九十]、\s*(.+)$', re.MULTILINE),  # 中文序号
        ]
        
        # 列表模式
        self.list_patterns = [
            re.compile(r'^\s*[•·▪▫◦‣⁃]\s+(.+)$', re.MULTILINE),  # 无序列表
            re.compile(r'^\s*\d+[.)、]\s+(.+)$', re.MULTILINE),  # 有序列表
            re.compile(r'^\s*[a-zA-Z][.)、]\s+(.+)$', re.MULTILINE),  # 字母列表
            re.compile(r'^\s*[①②③④⑤⑥⑦⑧⑨⑩]\s+(.+)$', re.MULTILINE),  # 圆圈数字
        ]
        
        # 表格模式
        self.table_pattern = re.compile(r'\|.*\|', re.MULTILINE)
        
        # 代码块模式
        self.code_patterns = [
            re.compile(r'```[\s\S]*?```', re.MULTILINE),  # Markdown代码块
            re.compile(r'`[^`]+`'),  # 行内代码
        ]
    
    def chunk(self, text: str, structure: Dict[str, Any] = None) -> List[Dict[str, Any]]:
        """按内容类型切片"""
        
        if not text:
            return []
        
        chunks = []
        lines = text.split('\n')
        current_chunk = []
        current_type = 'paragraph'
        chunk_id = 0
        
        for line in lines:
            line_type = self._identify_line_type(line)
            
            # 如果类型改变，保存当前块
            if line_type != current_type and current_chunk:
                chunk_content = '\n'.join(current_chunk).strip()
                if chunk_content:
                    chunk = self._create_chunk(chunk_content, current_type, chunk_id)
                    chunks.append(chunk)
                    chunk_id += 1
                
                current_chunk = []
                current_type = line_type
            
            current_chunk.append(line)
        
        # 处理最后一个块
        if current_chunk:
            chunk_content = '\n'.join(current_chunk).strip()
            if chunk_content:
                chunk = self._create_chunk(chunk_content, current_type, chunk_id)
                chunks.append(chunk)
        
        return chunks
    
    def _identify_line_type(self, line: str) -> str:
        """识别行的类型"""
        
        line = line.strip()
        
        if not line:
            return 'empty'
        
        # 检查标题
        for pattern in self.title_patterns:
            if pattern.match(line):
                return 'title'
        
        # 检查列表
        for pattern in self.list_patterns:
            if pattern.match(line):
                return 'list'
        
        # 检查表格
        if self.table_pattern.search(line):
            return 'table'
        
        # 检查代码
        for pattern in self.code_patterns:
            if pattern.search(line):
                return 'code'
        
        return 'paragraph'
    
    def _create_chunk(self, content: str, chunk_type: str, chunk_id: int) -> Dict[str, Any]:
        """创建切片对象"""
        
        return {
            'chunk_id': f'chunk_{chunk_id:03d}',
            'content': content,
            'metadata': {
                'chunk_type': chunk_type,
                'word_count': len(content.split()),
                'char_count': len(content),
                'level': 0
            }
        }

class StructuralChunking(ChunkingStrategy):
    """按文档结构切片策略"""
    
    def __init__(self, max_depth: int = 3, preserve_structure: bool = True, 
                 structure_levels: List[str] = None, include_headers: bool = True, 
                 max_section_size: int = 2000, **kwargs):
        self.max_depth = max_depth
        self.preserve_structure = preserve_structure
        self.structure_levels = structure_levels or ['section', 'subsection']
        self.include_headers = include_headers
        self.max_section_size = max_section_size
        
        print(f"[StructuralChunking] 初始化参数:")
        print(f"[StructuralChunking] - max_depth: {self.max_depth}")
        print(f"[StructuralChunking] - preserve_structure: {self.preserve_structure}")
        print(f"[StructuralChunking] - structure_levels: {self.structure_levels}")
        print(f"[StructuralChunking] - include_headers: {self.include_headers}")
        print(f"[StructuralChunking] - max_section_size: {self.max_section_size}")
    
    def chunk(self, text: str, structure: Dict[str, Any] = None) -> List[Dict[str, Any]]:
        """按文档结构切片"""
        
        if not text:
            return []
        
        print(f"[StructuralChunking] 开始按文档结构切片，文本长度: {len(text)} 字符")
        
        # 如果有结构信息，使用结构信息
        if structure and 'headings' in structure:
            print(f"[StructuralChunking] 使用已知结构信息，标题数量: {len(structure['headings'])}")
            chunks = self._chunk_by_structure(text, structure)
        else:
            # 否则尝试自动识别结构
            print(f"[StructuralChunking] 自动识别文档结构")
            chunks = self._chunk_by_auto_structure(text)
        
        # 应用最大切片大小限制
        if self.max_section_size > 0:
            chunks = self._apply_size_limit(chunks)
        
        print(f"[StructuralChunking] 按文档结构切片完成，生成 {len(chunks)} 个切片")
        return chunks
    
    def _chunk_by_structure(self, text: str, structure: Dict[str, Any]) -> List[Dict[str, Any]]:
        """根据已知结构切片"""
        
        chunks = []
        headings = structure.get('headings', [])
        
        if not headings:
            print(f"[StructuralChunking] 结构信息中没有标题，使用自动识别")
            return self._chunk_by_auto_structure(text)
        
        print(f"[StructuralChunking] 处理 {len(headings)} 个标题")
        
        # 过滤标题级别
        if self.structure_levels:
            filtered_headings = []
            level_map = {'section': 1, 'subsection': 2, 'subsubsection': 3}
            allowed_levels = [level_map.get(level, int(level) if level.isdigit() else 1) for level in self.structure_levels]
            
            for heading in headings:
                heading_level = heading.get('level', 1)
                if heading_level in allowed_levels:
                    filtered_headings.append(heading)
            
            print(f"[StructuralChunking] 根据structure_levels过滤后剩余 {len(filtered_headings)} 个标题")
            headings = filtered_headings
        
        # 改进的文本定位方法：直接在文本中查找标题
        lines = text.split('\n')
        
        # 为每个标题找到在文本中的行号
        heading_positions = []
        for heading in headings:
            heading_text = heading.get('text', '').strip()
            found_line = -1
            
            # 在文本中查找标题
            for i, line in enumerate(lines):
                line_clean = line.strip()
                # 尝试多种匹配方式
                if (line_clean == heading_text or 
                    line_clean.endswith(heading_text) or
                    heading_text in line_clean):
                    found_line = i
                    break
            
            if found_line == -1:
                print(f"[StructuralChunking] 警告：未找到标题 '{heading_text}' 在文本中的位置")
                # 如果找不到，尝试使用段落索引估算
                para_index = heading.get('paragraph_index', 0)
                found_line = min(para_index * 2, len(lines) - 1)  # 粗略估算
            
            heading_positions.append({
                'heading': heading,
                'line_num': found_line,
                'text': heading_text
            })
        
        # 按行号排序
        heading_positions.sort(key=lambda x: x['line_num'])
        
        print(f"[StructuralChunking] 找到 {len(heading_positions)} 个标题位置")
        
        # 根据标题位置切片
        for i, pos_info in enumerate(heading_positions):
            start_line = pos_info['line_num']
            
            # 确定结束位置
            if i + 1 < len(heading_positions):
                end_line = heading_positions[i + 1]['line_num']
            else:
                end_line = len(lines)
            
            # 提取内容
            section_lines = lines[start_line:end_line]
            section_content = '\n'.join(section_lines).strip()
            
            # 如果不包含标题，移除第一行（标题行）
            if not self.include_headers and section_lines:
                section_content = '\n'.join(section_lines[1:]).strip()
            
            if section_content:
                heading = pos_info['heading']
                chunk = {
                    'chunk_id': f'chunk_{i:03d}',
                    'content': section_content,
                    'metadata': {
                        'chunk_type': 'section',
                        'title': heading.get('text', ''),
                        'level': heading.get('level', 1),
                        'start_pos': start_line,
                        'end_pos': end_line,
                        'word_count': len(section_content.split()),
                        'char_count': len(section_content),
                        'include_headers': self.include_headers,
                        'structure_levels': self.structure_levels
                    }
                }
                chunks.append(chunk)
                print(f"[StructuralChunking] 创建切片 {i+1}: {heading.get('text', '')[:50]}... ({len(section_content)} 字符)")
        
        print(f"[StructuralChunking] 基于结构信息生成 {len(chunks)} 个切片")
        
        # 如果没有生成有效切片，回退到自动识别
        if not chunks:
            print(f"[StructuralChunking] 结构切片失败，回退到自动识别")
            return self._chunk_by_auto_structure(text)
        
        return chunks
    
    def _chunk_by_auto_structure(self, text: str) -> List[Dict[str, Any]]:
        """自动识别结构并切片"""
        
        # 识别标题
        headings = self._extract_headings(text)
        
        if not headings:
            # 如果没有标题，按段落切片
            return self._chunk_by_paragraphs(text)
        
        chunks = []
        lines = text.split('\n')
        chunk_id = 0
        
        # 处理文档开头到第一个标题之间的内容
        first_heading_line = headings[0]['line_num'] if headings else len(lines)
        if first_heading_line > 0:
            intro_content = '\n'.join(lines[:first_heading_line]).strip()
            if intro_content:
                chunk = {
                    'chunk_id': f'chunk_{chunk_id:03d}',
                    'content': intro_content,
                    'metadata': {
                        'chunk_type': 'introduction',
                        'title': '文档开头',
                        'level': 0,
                        'start_pos': 0,
                        'end_pos': len(intro_content),
                        'word_count': len(intro_content.split()),
                        'char_count': len(intro_content)
                    }
                }
                chunks.append(chunk)
                chunk_id += 1
        
        # 处理每个标题及其内容
        for i, heading in enumerate(headings):
            start_line = heading['line_num']
            # 确定内容结束位置
            if i + 1 < len(headings):
                end_line = headings[i + 1]['line_num']
            else:
                end_line = len(lines)
            
            # 提取标题行和内容
            section_lines = lines[start_line:end_line]
            section_content = '\n'.join(section_lines).strip()
            
            if section_content:
                chunk = {
                    'chunk_id': f'chunk_{chunk_id:03d}',
                    'content': section_content,
                    'metadata': {
                        'chunk_type': 'section',
                        'title': heading['text'],
                        'level': heading['level'],
                        'heading_type': heading['type'],
                        'start_pos': start_line,
                        'end_pos': end_line,
                        'word_count': len(section_content.split()),
                        'char_count': len(section_content)
                    }
                }
                chunks.append(chunk)
                chunk_id += 1
        
        return chunks if chunks else self._chunk_by_paragraphs(text)
    
    def _apply_size_limit(self, chunks: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
        """应用最大切片大小限制"""
        
        print(f"[StructuralChunking] 应用最大切片大小限制: {self.max_section_size} 字符")
        
        limited_chunks = []
        
        for chunk in chunks:
            content = chunk['content']
            char_count = chunk['metadata']['char_count']
            
            if char_count <= self.max_section_size:
                # 切片大小在限制内，直接添加
                limited_chunks.append(chunk)
            else:
                # 切片过大，需要进一步分割
                print(f"[StructuralChunking] 切片过大 ({char_count} 字符)，进行分割")
                sub_chunks = self._split_large_chunk(chunk)
                limited_chunks.extend(sub_chunks)
        
        # 重新分配chunk_id
        for i, chunk in enumerate(limited_chunks):
            chunk['chunk_id'] = f'chunk_{i:03d}'
            chunk['metadata']['chunk_index'] = i
            chunk['metadata']['total_chunks'] = len(limited_chunks)
        
        print(f"[StructuralChunking] 大小限制应用完成，最终切片数: {len(limited_chunks)}")
        return limited_chunks
    
    def _split_large_chunk(self, chunk: Dict[str, Any]) -> List[Dict[str, Any]]:
        """分割过大的切片"""
        
        content = chunk['content']
        metadata = chunk['metadata'].copy()
        
        # 按段落分割
        paragraphs = content.split('\n\n')
        sub_chunks = []
        current_content = []
        current_length = 0
        
        for para in paragraphs:
            para = para.strip()
            if not para:
                continue
            
            para_length = len(para)
            
            if current_length + para_length <= self.max_section_size:
                current_content.append(para)
                current_length += para_length + 2  # +2 for \n\n
            else:
                # 保存当前累积的内容
                if current_content:
                    sub_chunk_content = '\n\n'.join(current_content)
                    sub_chunk = {
                        'chunk_id': f'temp_{len(sub_chunks)}',
                        'content': sub_chunk_content,
                        'metadata': {
                            **metadata,
                            'char_count': len(sub_chunk_content),
                            'word_count': len(sub_chunk_content.split()),
                            'is_split': True
                        }
                    }
                    sub_chunks.append(sub_chunk)
                
                # 开始新的切片
                current_content = [para]
                current_length = para_length
        
        # 处理最后的内容
        if current_content:
            sub_chunk_content = '\n\n'.join(current_content)
            sub_chunk = {
                'chunk_id': f'temp_{len(sub_chunks)}',
                'content': sub_chunk_content,
                'metadata': {
                    **metadata,
                    'char_count': len(sub_chunk_content),
                    'word_count': len(sub_chunk_content.split()),
                    'is_split': True
                }
            }
            sub_chunks.append(sub_chunk)
        
        print(f"[StructuralChunking] 大切片分割为 {len(sub_chunks)} 个子切片")
        return sub_chunks
    
    def _extract_headings(self, text: str) -> List[Dict[str, Any]]:
        """提取标题信息"""
        
        headings = []
        lines = text.split('\n')
        
        for i, line in enumerate(lines):
            heading_info = self._is_heading_line(line, i)
            if heading_info:
                heading_info['line_num'] = i
                headings.append(heading_info)
        
        return headings
    
    def _is_heading_line(self, line: str, line_num: int) -> Optional[Dict[str, Any]]:
        """判断是否是标题行"""
        
        line = line.strip()
        
        if not line:
            return None
        
        # Markdown标题
        md_match = re.match(r'^(#{1,6})\s+(.+)$', line)
        if md_match:
            level = len(md_match.group(1))
            title = md_match.group(2)
            return {
                'text': title,
                'level': level,
                'line_num': line_num,
                'type': 'markdown'
            }
        
        # 扩展的中文章节标题模式
        cn_patterns = [
            # 传统章节格式
            (r'^第[一二三四五六七八九十\d]+[章节部分]\s*(.*)$', 1),
            # 数字标题格式
            (r'^\d+\.\s+(.+)$', 2),
            (r'^\d+\s+(.+)$', 2),
            # 中文序号
            (r'^[一二三四五六七八九十]、\s*(.+)$', 2),
            # 学术论文常见格式
            (r'^\d+\.\d+\s+(.+)$', 3),
            (r'^\d+\.\d+\.\d+\s+(.+)$', 4),
            # 摘要、引言、结论等关键词
            (r'^(摘要|引言|绪论|结论|参考文献|致谢|附录)\s*(.*)$', 1),
            (r'^(Abstract|Introduction|Conclusion|References|Acknowledgments|Appendix)\s*(.*)$', 1),
            # 居中标题（通常较短且独占一行）
            (r'^(.{1,20})$', 2) if len(line) <= 20 and not re.search(r'[，。！？；：]', line) else None
        ]
        
        for pattern_info in cn_patterns:
            if pattern_info is None:
                continue
            pattern, level = pattern_info
            match = re.match(pattern, line, re.IGNORECASE)
            if match:
                title = match.group(1) if match.lastindex >= 1 else line
                # 如果有第二个捕获组，使用它作为标题
                if match.lastindex >= 2 and match.group(2):
                    title = match.group(2)
                return {
                    'text': title,
                    'level': level,
                    'line_num': line_num,
                    'type': 'chinese'
                }
        
        return None
    
    def _create_section_chunk(self, content: str, heading_info: Optional[Dict[str, Any]], chunk_id: int) -> Dict[str, Any]:
        """创建段落切片"""
        
        metadata = {
            'chunk_type': 'section',
            'word_count': len(content.split()),
            'char_count': len(content),
            'level': heading_info.get('level', 0) if heading_info else 0
        }
        
        if heading_info:
            metadata.update({
                'title': heading_info.get('text', ''),
                'heading_type': heading_info.get('type', '')
            })
        
        return {
            'chunk_id': f'chunk_{chunk_id:03d}',
            'content': content,
            'metadata': metadata
        }
    
    def _chunk_by_paragraphs(self, text: str) -> List[Dict[str, Any]]:
        """按段落切片"""
        
        paragraphs = text.split('\n\n')
        chunks = []
        
        for i, para in enumerate(paragraphs):
            para = para.strip()
            if para:
                chunk = {
                    'chunk_id': f'chunk_{i:03d}',
                    'content': para,
                    'metadata': {
                        'chunk_type': 'paragraph',
                        'word_count': len(para.split()),
                        'char_count': len(para),
                        'level': 0
                    }
                }
                chunks.append(chunk)
        
        return chunks

class HierarchicalChunking(ChunkingStrategy):
    """层级结构切片策略"""
    
    def __init__(self, max_depth: int = 3):
        self.max_depth = max_depth
    
    def chunk(self, text: str, structure: Dict[str, Any] = None) -> List[Dict[str, Any]]:
        """按层级结构切片"""
        
        if not text:
            return []
        
        print(f"[HierarchicalChunking] 开始层级结构切片，文本长度: {len(text)} 字符")
        
        # 首先识别文档中的标题结构
        lines = text.split('\n')
        headings = []
        
        # 识别标题
        for i, line in enumerate(lines):
            line = line.strip()
            if not line:
                continue
                
            # 检查是否是标题
            heading_info = self._detect_heading(line, i)
            if heading_info:
                headings.append(heading_info)
        
        print(f"[HierarchicalChunking] 识别到 {len(headings)} 个标题")
        
        if not headings:
            # 如果没有标题，按段落切片
            return self._chunk_by_paragraphs(text)
        
        # 按标题层级切片
        chunks = []
        
        for i, heading in enumerate(headings):
            start_line = heading['line_num']
            # 确定内容结束位置
            if i + 1 < len(headings):
                end_line = headings[i + 1]['line_num']
            else:
                end_line = len(lines)
            
            # 提取内容
            section_lines = lines[start_line:end_line]
            section_content = '\n'.join(section_lines).strip()
            
            if section_content:
                chunk = {
                    'chunk_id': f'chunk_{i:03d}',
                    'content': section_content,
                    'metadata': {
                        'chunk_type': 'hierarchical_section',
                        'title': heading['text'],
                        'level': heading['level'],
                        'heading_type': heading['type'],
                        'start_line': start_line,
                        'end_line': end_line - 1,
                        'word_count': len(section_content.split()),
                        'char_count': len(section_content)
                    }
                }
                chunks.append(chunk)
        
        # 构建层级关系
        hierarchical_chunks = self._build_hierarchy(chunks)
        
        print(f"[HierarchicalChunking] 生成 {len(hierarchical_chunks)} 个层级切片")
        return hierarchical_chunks
    
    def _detect_heading(self, line: str, line_num: int) -> Optional[Dict[str, Any]]:
        """检测标题行"""
        
        line = line.strip()
        if not line:
            return None
        
        # Markdown标题
        md_match = re.match(r'^(#{1,6})\s+(.+)$', line)
        if md_match:
            level = len(md_match.group(1))
            title = md_match.group(2)
            return {
                'text': title,
                'level': level,
                'line_num': line_num,
                'type': 'markdown'
            }
        
        # 中文标题模式
        cn_patterns = [
            (r'^第[一二三四五六七八九十\d]+[章节部分]\s*(.*)$', 1),
            (r'^\d+\.\s+(.+)$', 2),
            (r'^\d+\s+(.+)$', 2),
            (r'^[一二三四五六七八九十]、\s*(.+)$', 2),
            (r'^\d+\.\d+\s+(.+)$', 3),
            (r'^\d+\.\d+\.\d+\s+(.+)$', 4),
            (r'^(摘要|引言|绪论|结论|参考文献|致谢|附录)\s*(.*)$', 1),
            (r'^(Abstract|Introduction|Conclusion|References|Acknowledgments|Appendix)\s*(.*)$', 1),
        ]
        
        for pattern, level in cn_patterns:
            match = re.match(pattern, line, re.IGNORECASE)
            if match:
                title = match.group(1) if match.lastindex >= 1 else line
                if match.lastindex >= 2 and match.group(2):
                    title = match.group(2)
                return {
                    'text': title,
                    'level': level,
                    'line_num': line_num,
                    'type': 'chinese'
                }
        
        return None
    
    def _chunk_by_paragraphs(self, text: str) -> List[Dict[str, Any]]:
        """按段落切片"""
        
        paragraphs = text.split('\n\n')
        chunks = []
        
        for i, para in enumerate(paragraphs):
            para = para.strip()
            if para:
                chunk = {
                    'chunk_id': f'chunk_{i:03d}',
                    'content': para,
                    'metadata': {
                        'chunk_type': 'paragraph',
                        'word_count': len(para.split()),
                        'char_count': len(para),
                        'level': 0
                    }
                }
                chunks.append(chunk)
        
        return chunks
    
    def _build_hierarchy(self, chunks: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
        """构建层级关系"""
        
        if not chunks:
            return []
        
        # 为每个切片分配父子关系
        for i, chunk in enumerate(chunks):
            chunk_level = chunk['metadata'].get('level', 0)
            
            # 寻找父节点
            parent_id = None
            for j in range(i - 1, -1, -1):
                parent_level = chunks[j]['metadata'].get('level', 0)
                if parent_level < chunk_level:
                    parent_id = chunks[j]['chunk_id']
                    break
            
            # 寻找子节点
            children_ids = []
            for j in range(i + 1, len(chunks)):
                child_level = chunks[j]['metadata'].get('level', 0)
                if child_level <= chunk_level:
                    break
                if child_level == chunk_level + 1:
                    children_ids.append(chunks[j]['chunk_id'])
            
            # 更新元数据
            chunk['metadata'].update({
                'parent_id': parent_id,
                'children_ids': children_ids
            })
        
        return chunks

class CustomSeparatorChunking(ChunkingStrategy):
    """自定义分隔符切片策略"""
    
    def __init__(self, separators: str = '\n\n', priority: str = 'first_match', keep_delimiter: bool = False):
        # 处理多个分隔符
        if isinstance(separators, str):
            # 按行分割分隔符
            self.separators = [sep.strip() for sep in separators.split('\n') if sep.strip()]
        else:
            self.separators = separators if separators else ['\n\n']
        
        self.priority = priority
        self.keep_delimiter = keep_delimiter
        
        print(f"[CustomSeparatorChunking] 初始化分隔符: {self.separators}")
        print(f"[CustomSeparatorChunking] 优先级: {self.priority}")
        print(f"[CustomSeparatorChunking] 保留分隔符: {self.keep_delimiter}")
    
    def chunk(self, text: str, structure: Dict[str, Any] = None) -> List[Dict[str, Any]]:
        """按自定义分隔符切片"""
        
        if not text:
            return []
        
        print(f"[CustomSeparatorChunking] 开始切片，文本长度: {len(text)}")
        print(f"[CustomSeparatorChunking] 使用分隔符: {self.separators}")
        
        # 使用多个分隔符进行切片
        parts = self._split_by_separators(text)
        chunks = []
        
        print(f"[CustomSeparatorChunking] 切分后得到 {len(parts)} 个部分")
        
        for i, part in enumerate(parts):
            part_content = part.strip()
            if part_content:
                chunk = {
                    'chunk_id': f'chunk_{i:03d}',
                    'content': part_content,
                    'metadata': {
                        'chunk_type': 'custom_separator',
                        'separators': self.separators,
                        'priority': self.priority,
                        'word_count': len(part_content.split()),
                        'char_count': len(part_content),
                        'level': 0
                    }
                }
                chunks.append(chunk)
                print(f"[CustomSeparatorChunking] 创建切片 {i}: {len(part_content)} 字符")
        
        print(f"[CustomSeparatorChunking] 最终生成 {len(chunks)} 个切片")
        return chunks
    
    def _split_by_separators(self, text: str) -> List[str]:
        """使用多个分隔符切分文本"""
        
        if not self.separators:
            return [text]
        
        # 如果只有一个分隔符，直接切分
        if len(self.separators) == 1:
            separator = self.separators[0]
            print(f"[CustomSeparatorChunking] 使用单个分隔符切分: '{separator}'")
            parts = text.split(separator)
            print(f"[CustomSeparatorChunking] 单分隔符切分结果: {len(parts)} 个部分")
            return parts
        
        # 多个分隔符的情况
        print(f"[CustomSeparatorChunking] 使用多个分隔符切分: {self.separators}")
        
        # 按优先级处理
        if self.priority == 'first_match':
            return self._split_first_match(text)
        elif self.priority == 'longest_match':
            return self._split_longest_match(text)
        elif self.priority == 'shortest_match':
            return self._split_shortest_match(text)
        else:
            return self._split_first_match(text)
    
    def _split_first_match(self, text: str) -> List[str]:
        """按第一个匹配的分隔符切分"""
        
        for separator in self.separators:
            if separator in text:
                print(f"[CustomSeparatorChunking] 首次匹配分隔符: '{separator}'")
                parts = text.split(separator)
                print(f"[CustomSeparatorChunking] 首次匹配切分结果: {len(parts)} 个部分")
                return parts
        
        print(f"[CustomSeparatorChunking] 没有找到匹配的分隔符，返回原文本")
        return [text]
    
    def _split_longest_match(self, text: str) -> List[str]:
        """按最长匹配的分隔符切分"""
        
        best_separator = None
        max_length = 0
        
        for separator in self.separators:
            if separator in text and len(separator) > max_length:
                best_separator = separator
                max_length = len(separator)
        
        if best_separator:
            print(f"[CustomSeparatorChunking] 最长匹配分隔符: '{best_separator}'")
            return text.split(best_separator)
        
        return [text]
    
    def _split_shortest_match(self, text: str) -> List[str]:
        """按最短匹配的分隔符切分"""
        
        best_separator = None
        min_length = float('inf')
        
        for separator in self.separators:
            if separator in text and len(separator) < min_length:
                best_separator = separator
                min_length = len(separator)
        
        if best_separator:
            print(f"[CustomSeparatorChunking] 最短匹配分隔符: '{best_separator}'")
            return text.split(best_separator)
        
        return [text]

class QuestionBasedChunking(ChunkingStrategy):
    """基于题目结构的切片策略"""
    
    def __init__(self, question_pattern: str = r'^\d+\.'):
        self.question_pattern = re.compile(question_pattern, re.MULTILINE)
    
    def chunk(self, text: str, structure: Dict[str, Any] = None) -> List[Dict[str, Any]]:
        """按题目结构切片"""
        
        if not text:
            return []
        
        print(f"[QuestionBasedChunking] 开始题目结构切片，文本长度: {len(text)} 字符")
        
        # 使用正则表达式分割文本，保留分隔符
        parts = re.split(r'(?=\d+\.)', text)
        parts = [part.strip() for part in parts if part.strip()]
        
        print(f"[QuestionBasedChunking] 按题目模式分割后得到 {len(parts)} 个部分")
        
        chunks = []
        chunk_count = 0
        
        for i, part in enumerate(parts):
            if part.strip():
                # 检查是否以数字+点开头
                if re.match(r'^\d+\.', part.strip()):
                    chunk_type = 'question'
                else:
                    chunk_type = 'header'
                
                chunk = self._create_chunk(part.strip(), chunk_count, chunk_type)
                chunks.append(chunk)
                chunk_count += 1
                print(f"[QuestionBasedChunking] 创建切片 {chunk_count}: 类型={chunk_type}, 长度={len(part.strip())} 字符")
        
        # 过滤掉长度为1的header切片（可能是分割产生的空白）
        filtered_chunks = []
        final_chunk_count = 0
        
        for chunk in chunks:
            if chunk['metadata']['chunk_type'] == 'header' and chunk['metadata']['char_count'] <= 2:
                print(f"[QuestionBasedChunking] 跳过长度过短的标题切片: {chunk['metadata']['char_count']} 字符")
                continue
            
            # 重新分配chunk_id
            chunk['chunk_id'] = f'chunk_{final_chunk_count:03d}'
            chunk['metadata']['chunk_index'] = final_chunk_count
            filtered_chunks.append(chunk)
            final_chunk_count += 1
        
        print(f"[QuestionBasedChunking] 题目结构切片完成，生成 {len(filtered_chunks)} 个有效切片")
        return filtered_chunks
    
    def _create_chunk(self, content: str, index: int, chunk_type: str = 'question') -> Dict[str, Any]:
        """创建切片对象"""
        
        # 提取题号（如果是题目）
        question_number = None
        if chunk_type == 'question':
            match = self.question_pattern.match(content)
            if match:
                question_number = content.split('.')[0]
        
        chunk = {
            'chunk_id': f'chunk_{index:03d}',
            'content': content,
            'metadata': {
                'chunk_type': chunk_type,
                'question_number': question_number,
                'word_count': len(content.split()),
                'char_count': len(content),
                'level': 0,
                'has_answer': '答案：' in content or '答案:' in content
            }
        }
        
        return chunk

class ChunkingEngine:
    """切片引擎主类"""
    
    def __init__(self, config: Dict[str, Any]):
        self.config = config
        self.strategies = self._initialize_strategies()
    
    def _initialize_strategies(self) -> Dict[str, ChunkingStrategy]:
        """初始化切片策略"""
        
        # 获取自定义分隔符配置
        delimiters = self.config.get('delimiters', self.config.get('custom_separator', '\n\n'))
        delimiter_priority = self.config.get('delimiter_priority', 'first_match')
        keep_delimiter = self.config.get('keep_delimiter', False)
        
        print(f"[ChunkingEngine] 初始化自定义分隔符配置:")
        print(f"[ChunkingEngine] - 分隔符: {delimiters}")
        print(f"[ChunkingEngine] - 优先级: {delimiter_priority}")
        print(f"[ChunkingEngine] - 保留分隔符: {keep_delimiter}")
        
        # 创建结构化切片实例
        structural_chunking = StructuralChunking(
            max_depth=self.config.get('max_depth', 3),
            preserve_structure=self.config.get('preserve_structure', True),
            structure_levels=self.config.get('structure_levels', ['section', 'subsection']),
            include_headers=self.config.get('include_headers', True),
            max_section_size=self.config.get('max_section_size', 2000)
        )
        
        strategies = {
            '固定长度分段': FixedLengthChunking(
                chunk_size=self.config.get('chunk_size', 500),
                overlap_size=self.config.get('overlap_size', 50)
            ),
            '按内容类型分段': ContentTypeChunking(),
            '按文档结构分段': structural_chunking,
            'structural': structural_chunking,  # 添加英文别名
            '父子结构分段': HierarchicalChunking(
                max_depth=self.config.get('max_depth', 3)
            ),
            '按指定符号分段': CustomSeparatorChunking(
                separators=delimiters,
                priority=delimiter_priority,
                keep_delimiter=keep_delimiter
            ),
            '自定义分隔符分段': CustomSeparatorChunking(
                separators=delimiters,
                priority=delimiter_priority,
                keep_delimiter=keep_delimiter
            ),
            '题目结构分段': QuestionBasedChunking(
                question_pattern=self.config.get('question_pattern', r'^\d+\.')
            )
        }
        
        return strategies
    
    def chunk_document(self, text: str, structure: Dict[str, Any] = None) -> List[Dict[str, Any]]:
        """对文档进行切片"""
        
        try:
            print(f"[ChunkingEngine] 开始文档切片，文本长度: {len(text)} 字符")
            
            strategy_name = self.config.get('strategy', '固定长度分段')
            print(f"[ChunkingEngine] 使用切片策略: {strategy_name}")
            
            strategy = self.strategies.get(strategy_name)
            
            if not strategy:
                raise ValueError(f"不支持的切片策略: {strategy_name}")
            
            print(f"[ChunkingEngine] 执行切片操作...")
            chunks = strategy.chunk(text, structure)
            print(f"[ChunkingEngine] 切片完成，生成 {len(chunks)} 个切片")
            
            # 后处理：添加全局信息
            print(f"[ChunkingEngine] 添加全局元数据...")
            for i, chunk in enumerate(chunks):
                chunk['metadata'].update({
                    'chunk_index': i,
                    'total_chunks': len(chunks),
                    'strategy_used': strategy_name
                })
            
            print(f"[ChunkingEngine] 文档切片完成")
            return chunks
            
        except Exception as e:
            print(f"[ChunkingEngine] 切片过程中出错: {str(e)}")
            import traceback
            print(f"[ChunkingEngine] 错误堆栈: {traceback.format_exc()}")
            raise
    
    def get_available_strategies(self) -> List[str]:
        """获取可用的切片策略"""
        return list(self.strategies.keys())
    
    def preview_chunking(self, text: str, max_chunks: int = 5) -> List[Dict[str, Any]]:
        """预览切片效果"""
        
        chunks = self.chunk_document(text)
        
        # 只返回前几个切片用于预览
        preview_chunks = chunks[:max_chunks]
        
        # 添加预览标记
        for chunk in preview_chunks:
            chunk['metadata']['is_preview'] = True
        
        return preview_chunks